package com.opages.platform.common.config;


import com.opages.platform.common.config.basic.AbstractConfiguration;
import com.opages.platform.common.config.file.FileConfig;
import com.opages.platform.common.config.file.FileConfigFactory;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;

public class FileConfiguration extends AbstractConfiguration {
    private static final Logger LOGGER = LoggerFactory.getLogger(FileConfiguration.class);
    public static final String SYS_FILE_RESOURCE_PREFIX = "file:";
    private FileConfig fileConfig;

    public FileConfiguration() {
        fileConfig = FileConfigFactory.load();
    }

    public FileConfiguration(String name) {
        LOGGER.info("The file name of the operation is {}", name);
        File file = getConfigFile(name);
        if (file != null && file.exists()) {
            fileConfig = FileConfigFactory.load(file, name);
        }else {
            fileConfig = FileConfigFactory.load();
        }
    }

    private File getConfigFile(String name) {
        try {
            if (name == null) {
                throw new IllegalArgumentException("name can't be null");
            }
            boolean filePathCustom = name.startsWith(SYS_FILE_RESOURCE_PREFIX);
            String filePath = filePathCustom ? name.substring(SYS_FILE_RESOURCE_PREFIX.length()) : name;
            String decodedPath = URLDecoder.decode(filePath, StandardCharsets.UTF_8.name());
            File targetFile = getFileFromFileSystem(decodedPath);
            if (targetFile != null) {
                if (LOGGER.isInfoEnabled()) {
                    LOGGER.info("The configuration file used is {}", targetFile.getPath());
                }
                return targetFile;
            }
            if (!filePathCustom) {
                File classpathFile = getFileFromClasspath(name);
                if (classpathFile != null) {
                    return classpathFile;
                }
            }
        } catch (UnsupportedEncodingException e) {
            LOGGER.error("decode name error: {}", e.getMessage(), e);
        }
        return null;
    }

    private File getFileFromFileSystem(String decodedPath) {
        URL resourceUrl = this.getClass().getClassLoader().getResource("");
        String[] tryPaths = null;
        if (resourceUrl != null) {
            tryPaths = new String[]{
                    // first: project dir
                    resourceUrl.getPath() + decodedPath,
                    // second: system path
                    decodedPath
            };
        } else {
            tryPaths = new String[]{
                    decodedPath
            };
        }
        for (String tryPath : tryPaths) {
            File targetFile = new File(tryPath);
            if (targetFile.exists()) {
                return targetFile;
            }

            for (String s : FileConfigFactory.getSuffixSet()) {
                targetFile = new File(tryPath + "." + s);
                if (targetFile.exists()) {
                    return targetFile;
                }
            }
            // try to append config suffix
        }

        return null;
    }

    private File getFileFromClasspath(String name) throws UnsupportedEncodingException {
        URL resource = this.getClass().getClassLoader().getResource(name);
        if (resource == null) {
            for (String s : FileConfigFactory.getSuffixSet()) {
                resource = this.getClass().getClassLoader().getResource(name + "." + s);
                if (resource != null) {
                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info("The configuration file used is {}", resource.getPath());
                    }
                    String path = resource.getPath();
                    path = URLDecoder.decode(path, StandardCharsets.UTF_8.name());
                    return new File(path);
                }
            }
        } else {
            //读取springboot的jar包中的配置文件
            InputStream stream = this.getClass().getClassLoader().getResourceAsStream(name);
            if(stream != null) {
                File targetFile = new File(name);
                try {
                    FileUtils.copyInputStreamToFile(stream, targetFile);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if(targetFile.exists()) {
                    return targetFile;
                }
            }
            if (LOGGER.isInfoEnabled()) {
                LOGGER.info("The configuration file used is {}", name);
            }
            String path = resource.getPath();
            path = URLDecoder.decode(path, StandardCharsets.UTF_8.name());
            return new File(path);
        }

        return null;
    }

    @Override
    public String getTypeName() {
        return ConfigType.file.name();
    }

    @Override
    public String getConfig(String dataId, String defaultValue) {
        String value = getConfigFromSysPro(dataId);
        if (value != null) {
            return value;
        }
        value = fileConfig.get(dataId);
        return StringUtils.isEmpty(value) ? defaultValue : value;
    }
}
